﻿//Copyright (c) 2009-2010, Andreas Grünwald
//All rights reserved.

using System;
using System.Globalization;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Navigation;
using System.Windows.Threading;
using Slf;
using Slf.Resolvers;
using yaTDL.Core;
using yaTDL.Core.Properties;
using yaTDL.Core.MVVM;
using yaTDL.Extensions;
using yaTDL.Properties;
using System.Windows.Input;
using System.Diagnostics;

namespace yaTDL
{    
    public partial class MainWindow : Window
    {

        #region Fields

        MainPage mainPage;

        /// <summary>
        /// Indicates whether animations are to be used ot not.
        /// </summary>
        bool enableAnimations;                                                 

        #endregion

        #region Properties


        /// <summary>
        /// Fades out the currently loaded frame.
        /// </summary>
        Storyboard animation_NavigationFadeIn { get { return (Storyboard)Resources["Animation_NavigationFadeIn"]; } } 

        /// <summary>
        /// Fades in the currently loaded frame.
        /// </summary>
        Storyboard animation_NavigationFadeOut { get { return (Storyboard)Resources["Animation_NavigationFadeOut"]; } }

        #endregion



        /// <summary>
        /// Initializes a new instace of Window1.
        /// </summary>
        public MainWindow()
        {

            //as MainWindow is the Startup-Window, it neeeds to initialize the Logger for yaTDL.Core
            setLogger();

            FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
            this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);


            ViewManager.RegisterView(this.showMainPageViewModel, typeof(MainPageViewModel));
            ViewManager.RegisterView(this.showLoginViewModel, typeof(LoginViewModel));
            ViewManager.RegisterView(this.showSettingsViewModel, typeof(SettingsViewModel));
            ViewManager.RegisterView(this.showSyncConflictViewModel, typeof(SyncConflictViewModel));
            ViewManager.RegisterView(this.showInputBoxViewModel, typeof(InputBoxViewModel));

            InitializeComponent();


            this.DataContext = new MainWindowViewModel();
          
            ApplicationSettings.Settings.PropertyChanged +=new System.ComponentModel.PropertyChangedEventHandler(Settings_PropertyChanged);
            animation_NavigationFadeOut.Completed += new EventHandler(Animation_NavigationFadeOut_Completed);            

            enableAnimations = true;

        }       


        #region showView Actions

        private void showMainPageViewModel(ViewModelBase viewModel, Action<object> callback)
        {
            if (Dispatcher.CheckAccess())
            {
                showMainPageViewModelExecute(viewModel, callback);
            }
            else
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { showMainPageViewModelExecute(viewModel, callback); }));
            }            
        }

        private void showMainPageViewModelExecute(ViewModelBase viewModel, Action<object> callback)
        {
            mainPage = new MainPage();
            mainPage.DataContext = viewModel;
            navigate(mainPage);
        }

        private void showLoginViewModel(ViewModelBase viewModel, Action<object> callback)
        {
            if (Dispatcher.CheckAccess())
            {
                showLoginViewModelExecute(viewModel, callback);
            }
            else
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { showLoginViewModelExecute(viewModel, callback); }));
            }
        }

        private void showLoginViewModelExecute(ViewModelBase viewModel, Action<object> callback)
        {
            LoginWindow view = new LoginWindow(viewModel as LoginViewModel);

            viewModel.CloseViewAction = view.Close;

            if (callback != null)
            {
                view.Closed += (s, e) => callback(viewModel);
            }

            this.Grid_Overlay.Visibility = Visibility.Visible;

            view.ShowDialog();

            this.Grid_Overlay.Visibility = Visibility.Hidden;
        }

        private void showSettingsViewModel(ViewModelBase viewModel, Action<object> callback)
        {
            if (Dispatcher.CheckAccess())
            {
                showSettingsViewModelExecute(viewModel, callback);
            }
            else
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { showSettingsViewModelExecute(viewModel, callback); }));
            }
        }

        private void showSettingsViewModelExecute(ViewModelBase viewModel, Action<object> callback)
        {
            SettingsPage sp = new SettingsPage();
            sp.DataContext = viewModel;

            viewModel.CloseViewAction = delegate { this.navigate(mainPage); };

            if (callback != null)
            {
                viewModel.Closed += (s, e) => callback(viewModel);
            }

            navigate(sp);
        }

        private void showSyncConflictViewModel(ViewModelBase viewModel, Action<object> callback)
        {
            if (Dispatcher.CheckAccess())
            {
                showSyncConflictViewModelExecute(viewModel, callback);
            }
            else
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { showSyncConflictViewModelExecute(viewModel, callback); }));
            }
        }

        private void showSyncConflictViewModelExecute(ViewModelBase viewModel, Action<object> callback)
        {
            SyncConflictDialog d = new SyncConflictDialog();
            d.DataContext = viewModel;

            viewModel.CloseViewAction = d.Close;

            if (callback != null)
            {
                d.Closed += (s, e) => callback(viewModel);
            }

            this.Grid_Overlay.Visibility = Visibility.Visible;

            d.ShowDialog();

            this.Grid_Overlay.Visibility = Visibility.Hidden;
        }

        private void showInputBoxViewModel(ViewModelBase viewModel, Action<object> callback)
        {
            if (Dispatcher.CheckAccess())
            {
                showInputBoxViewModelExecute(viewModel, callback);
            }
            else
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { showInputBoxViewModelExecute(viewModel, callback); }));
            }
        }

        private void showInputBoxViewModelExecute(ViewModelBase viewModel, Action<object> callback)
        {
            InputBox inputBox = new InputBox();
            inputBox.DataContext = viewModel;

            viewModel.CloseViewAction = inputBox.Close;

            if (callback != null)
            {
                inputBox.Closed += (s, e) => callback(viewModel);
            }

            this.Grid_Overlay.Visibility = Visibility.Visible;

            inputBox.ShowDialog();

            this.Grid_Overlay.Visibility = Visibility.Hidden;
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Loads the window's theme and assigns border_top.MouseDown and statusBar1.MouseDown to Window.DragMove(),
        /// so that the window can be drag-moved by clicking anywhere in the "glassified" area.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            if (GlassHelper.IsCompositionEnabled)
            {
                GlassHelper.ExtendGlassIntoClientArea(this, new Thickness(20));
            }
        }
        
        private void animation_OverlayFadeOut_Completed(object sender, EventArgs e)
        {
            Grid_Overlay.Visibility = Visibility.Collapsed;
        }

        private void Settings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "Logging_Enable":
                    setLogger();
                    break;
            }
        }


        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
            source.AddHook(new HwndSourceHook(WndProc));
        }

        private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {           
            UISettings.Default.Save();
            ApplicationSettings.Settings.Save();      
            
        }

        /// <summary>
        /// Handles WndProc messages sent to the window.
        /// </summary>
        /// <remarks>
        /// This method is based on code I found in the MSDN forums.
        /// Please visit http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6b97a6de-0480-4339-8ed0-cb7cdb27bd83/ to view the thread
        /// </remarks>               
        /// <param name="hwnd"></param>
        /// <param name="msg"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <param name="handled"></param>
        /// <returns></returns>
        [DebuggerStepThrough()]
        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == GlassHelper.WM_DWMCOMPOSITIONCHANGED)
            {
                if (GlassHelper.IsCompositionEnabled)                
                    GlassHelper.ExtendGlassIntoClientArea(this, new Thickness(20));               

                handled = true;
            }
            return IntPtr.Zero;
        }

        #endregion


        private static void setLogger()
        {
            if (ApplicationSettings.Settings.Logging_Enable)
                LoggerService.FactoryResolver = new SimpleFactoryResolver(new SLF.NLogFacade.NLogLoggerFactory());
            else
                LoggerService.SetLogger(null);
        }


        #region frame1 Navigation

        /// <summary>
        /// Loads the indicated Page into frame1
        /// </summary>
        private void navigate(Page nextPage)
        {
            this.nextPage = nextPage;       //saves the Page that has to be loaded so that setNextPage() can access it

            if (enableAnimations)           //if animations are enabled, the current content is faded out. Animation_NavigationFadeOut_Completed() will complete the remaining tasks to show nextPage
            {                
                animation_NavigationFadeOut.Begin();
            }
            else                            //if animations are disabled, the next page will simply be set without animation
            {
                frame1.Content = nextPage;
            }

        }

        /// <summary>
        /// The page that will be loaded next.
        /// </summary>
        private Page nextPage;

        /// <summary>
        /// Completes the tasks necessary to show nextPage afer fading out the old content has been completed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Animation_NavigationFadeOut_Completed(object sender, EventArgs e)
        {
            setNextPage();                          //sets the content of frame1

            animation_NavigationFadeIn.Begin(); //fades in frame1 (is not visible at this time)            
        }

        /// <summary>
        /// Displays nextPage in Frame1
        /// </summary>
        private void setNextPage()
        {
            frame1.Content = nextPage;
        }

        #endregion

      
        //Cancel event for the keyboard shortcus Ctrl+Tab and Ctrl+Shift+Tab as custom TabControls used in the application would throw an exception otherwise.
        private void Window_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (((Keyboard.Modifiers & ModifierKeys.Control) != 0 && e.Key == Key.Tab) || ((Keyboard.Modifiers & ModifierKeys.Control) != 0 && (Keyboard.Modifiers & ModifierKeys.Shift) != 0 && e.Key == Key.Tab))
            {
                e.Handled = true;
            }
        }

        

        
    }
}